package modules.cas.cas3;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * CAS算法
 *      比较并交换
 *      解决 ABA 问题
 *      比如一个线程1从内存位置V中取出A ，线程2也执行,将A–>B–>A，这时线程1进行CAS操作发现内存仍是A，然后线程1操作成功。
 * @author shengren.yan
 * @create 2021-04-15
 */
public class cas2 {
    // CAS : compareAndSet 比较并交换
    public static void main(String[] args) {

        // AtomicInteger的升级版 带版本号
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference(20,1);

        new Thread(()->{

            // 获得当前版本号
            int stamp = atomicStampedReference.getStamp();
            System.out.println("线程A - 当前的版本号：" + stamp + " 当前的值：" + atomicStampedReference.getReference());


            // 比较并交换 参数：期望的值、要修改的值、当前版本号、版本号更新的值
//            atomicStampedReference.compareAndSet(20,12,
//                    atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            // 打印，看是否修改成功
            System.out.println(atomicStampedReference.compareAndSet(20,12,
                    atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1));

            System.out.println("线程A - 当前的版本号：" + atomicStampedReference.getStamp() + " 当前的值：" + atomicStampedReference.getReference());

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 在把值改为原先的值
            System.out.println(atomicStampedReference.compareAndSet(12,20,
                    atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1));

            System.out.println("线程A - 当前的版本号：" + atomicStampedReference.getStamp() + " 当前的值：" + atomicStampedReference.getReference());

        },"线程A").start();


        new Thread(()->{

            // 获得当前版本号
            int stamp = atomicStampedReference.getStamp();
            System.out.println("线程B - 当前的版本号：" + atomicStampedReference.getStamp() + " 当前的值：" + atomicStampedReference.getReference());


            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicStampedReference.compareAndSet(20,200,
                    atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1));

            System.out.println("线程B - 当前的版本号：" + atomicStampedReference.getStamp() + " 当前的值：" + atomicStampedReference.getReference());


        },"线程B").start();


    }


}
